/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alemosbarbosa.com/

 Copyright (c) 2008-2010 Alexandre Lemos Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef CLASSES_H
#define CLASSES_H

#include "actions.h"
#include "cnome.h"
#include "directives.h"
#include "tokens.h"

namespace cnome {
template <typename ScannerT>
void
cpp::definition<ScannerT>::classes(cpp const& self)
    {
         using namespace actions;
         using namespace directive;
         using namespace util;

        class_name =
                template_id 
            |   CLASS_NAME
        ;
        
        class_specifier =
            remain_scope_d[	class_head >> LEFTBRACE >> EPSILON[&declareClassTmplPrms] >> !member_specification 
                            >> RIGHTBRACE ]
        ;

        class_head =
                (	class_key >> !(IDENTIFIER[&newClass_Name]||CLASS_NAME)[&enter_scope]
                    >> !base_clause )                            
            |	(	class_key 
                    >>	sss_d[ nested_name_specifier 
                        >> IDENTIFIER[&newClass_Name][&enter_scope] ]>> !base_clause ) 
            |	(	class_key 
                    >> sss_d[ nested_name_specifier >> TEMPLATE >>  template_id ] 
                    >> !base_clause )  // TODO (alb): Implement the handler of this rule 
        ;

        member_specification =
            ( member_declaration >> !member_specification ) |
            ( access_specifier >> COLON >> !member_specification )
        ;

        member_declaration =
                remain_scope_d[
                        remain_type_d[
                                decl_specifier_seq[&newTypeSpc] 
                            >>	!member_declarator_list 
                            >>	SEMICOLON
                        ]
                    |   
                        remain_type_d[
                                !member_declarator_list 
                            >>	SEMICOLON
                        ]
                ]
            |	remain_scope_d[
                    remain_type_d[ function_definition >> !SEMICOLON ] 
                ]
            |	remain_scope_d[
                    remain_type_d[
                        sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope]
                            >>	nested_name_specifier >> !TEMPLATE 
                            >>	unqualified_id[&newMember] ] >> SEMICOLON  
                    ]
                ]
            |	remain_scope_d[ using_declaration ]
            |	remain_scope_d[	template_declaration ]
            |   remain_scope_d[ explicit_specialization ]
        ;

        member_declarator_list =
            member_declarator >> member_declarator_list_helper
        ;

        member_declarator_list_helper =
                (	COMMA 	>> 	member_declarator 
                    >> member_declarator_list_helper  )
            |	EPSILON
        ;

        member_declarator =
                remain_scope_d[	
                        (		declarator 
                            >>	if_p(lookahead_d[COLON|LEFTPAREN])[NOTHING].else_p[EPSILON]  )[&newMember]
                    >>	!pure_specifier
                ] 
            |	remain_scope_d[	
                        (		declarator
                            >>  if_p(lookahead_d[COLON|LEFTPAREN])[NOTHING].else_p[EPSILON]  )[&newMember] 
                    >>	!constant_initializer  
                ]                 
            |	remain_scope_d[
                        !IDENTIFIER[&newMember] 
                    >>	COLON 
                    >>	constant_expression  
                ]  
        ;

        pure_specifier =
            ASSIGN >> INTLIT
        ;

        class_key =
            CLASS  |
            STRUCT |
            UNION  
        ;
        //  End grammar definition
          
        // turn on the debugging info.
        BOOST_SPIRIT_DEBUG_RULE(class_name);
        BOOST_SPIRIT_DEBUG_RULE(template_id);
        BOOST_SPIRIT_DEBUG_RULE(class_specifier);
        BOOST_SPIRIT_DEBUG_RULE(class_head);
        BOOST_SPIRIT_DEBUG_RULE(member_specification);
        BOOST_SPIRIT_DEBUG_RULE(member_declaration);
        BOOST_SPIRIT_DEBUG_RULE(access_specifier);
        BOOST_SPIRIT_DEBUG_RULE(decl_specifier_seq);
        BOOST_SPIRIT_DEBUG_RULE(member_declarator_list);
        BOOST_SPIRIT_DEBUG_RULE(function_definition);
        BOOST_SPIRIT_DEBUG_RULE(nested_name_specifier);
        BOOST_SPIRIT_DEBUG_RULE(unqualified_id);
        BOOST_SPIRIT_DEBUG_RULE(unqualified_id_raw);
        BOOST_SPIRIT_DEBUG_RULE(template_declaration);
        BOOST_SPIRIT_DEBUG_RULE(member_declarator);
        BOOST_SPIRIT_DEBUG_RULE(member_declarator_list_helper);
        BOOST_SPIRIT_DEBUG_RULE(declarator);
        BOOST_SPIRIT_DEBUG_RULE(pure_specifier);
        BOOST_SPIRIT_DEBUG_RULE(constant_initializer);
        BOOST_SPIRIT_DEBUG_RULE(constant_expression);
        BOOST_SPIRIT_DEBUG_RULE(template_id);
        BOOST_SPIRIT_DEBUG_RULE(base_clause);
        BOOST_SPIRIT_DEBUG_RULE(class_key);

        BOOST_SPIRIT_DEBUG_RULE(IDENTIFIER);
        BOOST_SPIRIT_DEBUG_RULE(LEFTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(RIGHTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(COLON);
        BOOST_SPIRIT_DEBUG_RULE(SEMICOLON);
        BOOST_SPIRIT_DEBUG_RULE(TEMPLATE);
        BOOST_SPIRIT_DEBUG_RULE(COLON_COLON);
        BOOST_SPIRIT_DEBUG_RULE(ASSIGN);
        BOOST_SPIRIT_DEBUG_RULE(INTLIT);
        BOOST_SPIRIT_DEBUG_RULE(EPSILON);
        BOOST_SPIRIT_DEBUG_RULE(CLASS);
        BOOST_SPIRIT_DEBUG_RULE(STRUCT); 
        BOOST_SPIRIT_DEBUG_RULE(UNION);
        BOOST_SPIRIT_DEBUG_RULE(CLASS_NAME);

    }
}  // namespace cnome

#endif // CLASSES_H
